/******************************************************************************
 * FileName:    gwin_board.c
 * Desc:        板载
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_board.h"
#include "miio_user_api.h"


/*-------------------------- Macro Definitions ------------------------------*/

/*-------------------------- Type Declarations ------------------------------*/

/*-------------------------- Global Variables -------------------------------*/

/*-------------------------- Local Variables --------------------------------*/

/*-------------------------- Functions Declarations -------------------------*/
static void gwin_wakeup_extern_init(void);
static void gwin_uart_init(void);


/*-------------------------- Functions Definitions --------------------------*/
/**
 * @brief 板载初始化
 */
void gwin_board_init(void)
{
    gwin_wakeup_extern_init();
    gwin_uart_init();
}


/*----------- 芯片驱动 瑞昱 -----------*/
/*----------- 串口 -----------*/
/**
 * @brief 中断函数对应表
 *      UART    UART0_IRQn      UART0_Handler
 *      UART1   UART1_IRQn      UART1_Handler
 *      UART2   UART2_IRQn      UART2_Handler
 */
/**
 * @brief 串口参数表
 */
static const struct _gwin_realtek_uart_cfg_map
{
    UART_TypeDef *uart;
    uint8_t tx;
    uint8_t rx;
    IRQn_Type channel;
    uint32_t apb_periph;
    uint32_t apb_periph_clock;
}gwin_realtek_uart_cfg_map[] =
{
    { UART,     UART0_TX,   UART0_RX,   UART0_IRQn,  APBPeriph_UART0,    APBPeriph_UART0_CLOCK },
    { UART1,    UART1_TX,   UART1_RX,   UART1_IRQn,  APBPeriph_UART1,    APBPeriph_UART1_CLOCK },
    { UART2,    UART2_TX,   UART2_RX,   UART2_IRQn,  APBPeriph_UART2,    APBPeriph_UART2_CLOCK },
};

/**
 * @brief 串口波特率
 */
typedef enum _gwin_realtek_uart_baud_rate
{
    GWIN_REALTEK_BAUD_RATE_NONE,
    GWIN_REALTEK_BAUD_RATE_1200,
    GWIN_REALTEK_BAUD_RATE_9600,
    GWIN_REALTEK_BAUD_RATE_38400,
    GWIN_REALTEK_BAUD_RATE_115200,
    GWIN_REALTEK_BAUD_RATE_921600,
}gwin_realtek_uart_baud_rate_t;

static const struct _gwin_realtek_uart_baud_rate_map
{
    uint16_t div;
    uint16_t ovsr;
    uint16_t ovsr_adj;
}gwin_realtek_uart_baud_rate_map[] =
{
    [GWIN_REALTEK_BAUD_RATE_1200] =         { 2589,     7,      0x7f7 },
    [GWIN_REALTEK_BAUD_RATE_9600] =         { 271,      10,     0x24A },
    [GWIN_REALTEK_BAUD_RATE_38400] =        { 85,       7,      0x222 },
    [GWIN_REALTEK_BAUD_RATE_115200] =       { 20,       12,     0x252 },
    [GWIN_REALTEK_BAUD_RATE_921600] =       { 4,        5,      0x3F7 },
};

/**
 * @brief 串口数据缓存
 */
typedef struct _gwin_uart_data
{
    uint8_t data[GWIN_UART_MAX_LEN];
    uint16_t len;
}gwin_uart_data_t;


/**
 * @brief 串口初始化
 */
static void gwin_realtek_uart_init(uint8_t uart_index, uint8_t uart_pin_tx, uint8_t uart_pin_rx, uint8_t baud_rate)
{
    Pad_Config(uart_pin_tx, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
    Pad_Config(uart_pin_rx, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);

    Pinmux_Config(uart_pin_tx, gwin_realtek_uart_cfg_map[uart_index].tx);
    Pinmux_Config(uart_pin_rx, gwin_realtek_uart_cfg_map[uart_index].rx);

    RCC_PeriphClockCmd(gwin_realtek_uart_cfg_map[uart_index].apb_periph, gwin_realtek_uart_cfg_map[uart_index].apb_periph_clock, ENABLE);

    /* uart init */
    UART_InitTypeDef UART_InitStruct;
    UART_StructInit(&UART_InitStruct);

    UART_InitStruct.div             = gwin_realtek_uart_baud_rate_map[baud_rate].div;
    UART_InitStruct.ovsr            = gwin_realtek_uart_baud_rate_map[baud_rate].ovsr;
    UART_InitStruct.ovsr_adj        = gwin_realtek_uart_baud_rate_map[baud_rate].ovsr_adj;
    UART_InitStruct.parity          = UART_PARITY_NO_PARTY;
    UART_InitStruct.stopBits        = UART_STOP_BITS_1;
    UART_InitStruct.wordLen         = UART_WROD_LENGTH_8BIT;
    UART_InitStruct.rxTriggerLevel  = 16;                      //1~29
    UART_InitStruct.idle_time       = UART_RX_IDLE_2BYTE;      //idle interrupt wait time
    UART_Init(gwin_realtek_uart_cfg_map[uart_index].uart, &UART_InitStruct);

    //enable rx interrupt and line status interrupt
    UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_RD_AVA, ENABLE);
    UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_IDLE, ENABLE);

    /*  Enable realtek_uart_cfg[uart].uart IRQ  */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel         = gwin_realtek_uart_cfg_map[uart_index].channel;
    NVIC_InitStruct.NVIC_IRQChannelCmd      = (FunctionalState)ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_Init(&NVIC_InitStruct);
}

/**
 * @brief 串口发送
 */
static void gwin_realtek_uart_send(uint8_t uart_index, const uint8_t *data, uint16_t len)
{
    uint8_t count;

    while (len / UART_TX_FIFO_SIZE > 0)
    {
        while (UART_GetFlagState(gwin_realtek_uart_cfg_map[uart_index].uart, UART_FLAG_THR_EMPTY) == 0);
        for (count = UART_TX_FIFO_SIZE; count > 0; count--)
        {
            gwin_realtek_uart_cfg_map[uart_index].uart->RB_THR = *data++;
        }
        len -= UART_TX_FIFO_SIZE;
    }

    while (UART_GetFlagState(gwin_realtek_uart_cfg_map[uart_index].uart, UART_FLAG_THR_EMPTY) == 0);
    while (len--)
    {
        gwin_realtek_uart_cfg_map[uart_index].uart->RB_THR = *data++;
    }
}

/**
 * @brief 串口中断入口
 */
static inline void gwin_realtek_uart_interrupt_handler(uint8_t uart_index, gwin_uart_recv_callback_t recv_callback, gwin_uart_data_t *recv)
{
    /* read interrupt id */
    uint32_t int_status = UART_GetIID(gwin_realtek_uart_cfg_map[uart_index].uart);

    /* disable interrupt */
    UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_RD_AVA, DISABLE);

    if (UART_GetFlagState(gwin_realtek_uart_cfg_map[uart_index].uart, UART_FLAG_RX_IDLE) == SET)
    {
        UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_IDLE, DISABLE);
        if (recv_callback != NULL)
        {
            int8_t ret = recv_callback(recv->data, recv->len);
            MI_LOG_INFO("uart %d recv_callback : len = %d, ret = %d", uart_index, recv->len, ret);
        }
        memset(recv, 0x00, sizeof(gwin_uart_data_t));
        UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_IDLE, ENABLE);
    }

    switch (int_status)
    {
            /* receiver line status  */
        case UART_INT_ID_LINE_STATUS:
            break;

            /*rx time out*/
        case UART_INT_ID_RX_TMEOUT:
            /* rx data valiable */
        case UART_INT_ID_RX_LEVEL_REACH:
            {
                uint8_t data = 0;
                while (UART_GetFlagState(gwin_realtek_uart_cfg_map[uart_index].uart, UART_FLAG_RX_DATA_RDY) == SET)
                {
                    data = UART_ReceiveByte(gwin_realtek_uart_cfg_map[uart_index].uart);
                    if (recv->len < sizeof(recv->data))
                    {
                        recv->data[recv->len++] = data;
                    }
                }
            }
            break;

            /* tx fifo empty */
        case UART_INT_ID_TX_EMPTY:
            /* do nothing */
            break;

            /* modem status */
        case UART_INT_ID_MODEM_STATUS:
            break;

        default:
            break;
    }

    /* enable interrupt again */
    UART_INTConfig(gwin_realtek_uart_cfg_map[uart_index].uart, UART_INT_RD_AVA, ENABLE);
}




/*----------- 唤醒外部 -----------*/
/**
 * @brief 初始化 唤醒外部
 */
static void gwin_wakeup_extern_init(void)
{
    RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);

    gwin_wakeup_extern_set_state(0);


    TIM_TimeBaseInitTypeDef TIM_InitStruct;
    TIM_StructInit(&TIM_InitStruct);

    TIM_InitStruct.TIM_PWM_En = PWM_DISABLE;
    TIM_InitStruct.TIM_Period = TIMER_WAKEUP_EXTERN_PERIOD ;
    TIM_InitStruct.TIM_Mode = TIM_Mode_UserDefine;
    TIM_InitStruct.TIM_SOURCE_DIV = TIM_CLOCK_DIVIDER_40;
    TIM_TimeBaseInit(TIMER_WAKEUP_EXTERN_NUM, &TIM_InitStruct);

    /*  Enable TIMER IRQ  */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIMER_WAKEUP_EXTERN_IRQN;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    TIM_ClearINT(TIMER_WAKEUP_EXTERN_NUM);
    TIM_INTConfig(TIMER_WAKEUP_EXTERN_NUM, ENABLE);
}

/**
 * @brief 设置 唤醒外部
 */
void gwin_wakeup_extern_set_state(uint8_t on)
{
    if (on)
    {
        TIM_ClearINT(TIMER_WAKEUP_EXTERN_NUM);
        TIM_Cmd(TIMER_WAKEUP_EXTERN_NUM, ENABLE);
    }

    on = (on > 0 ? GWIN_PIN_WAKEUP_EXTERN_VALID_LEVEL : !GWIN_PIN_WAKEUP_EXTERN_VALID_LEVEL);
    Pad_Config(GWIN_PIN_WAKEUP_EXTERN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, on > 0 ? PAD_OUT_HIGH : PAD_OUT_LOW);
}

/**
 * @brief AC定时器中断
 */
void TIMER_WAKEUP_EXTERN_HANDLER(void)
{
    TIM_ClearINT(TIMER_WAKEUP_EXTERN_NUM);
    TIM_Cmd(TIMER_WAKEUP_EXTERN_NUM, DISABLE);

    gwin_wakeup_extern_set_state(0);
}


/*----------- 串口 -----------*/
gwin_uart_recv_callback_t _uart_recv_data_parse = NULL;
static gwin_uart_data_t gwin_uart_data = { 0x00 };

/**
 * @brief 串口初始化
 */
void gwin_uart_init(void)
{
    gwin_realtek_uart_init(GINW_UARTx, GWIN_PIN_UART_TX, GWIN_PIN_UART_RX, GWIN_REALTEK_BAUD_RATE_9600);
}

/**
 * @brief 串口发送
 */
void gwin_uart_send(const uint8_t *data, uint16_t len)
{
    gwin_realtek_uart_send(GINW_UARTx, data, len);
}

/**
 * @brief 串口中断回调
 */
void gwin_uart_interrupt_set_callback(gwin_uart_recv_callback_t recv_callback)
{
    _uart_recv_data_parse = recv_callback;
}

/**
 * @brief 串口中断入口
 */
void GWIN_UART_HANDLER(void)
{
    gwin_realtek_uart_interrupt_handler(GINW_UARTx, _uart_recv_data_parse, &gwin_uart_data);
}


/*----------- 低功耗 -----------*/
/**
 * @brief 唤醒引脚
 */
static const uint8_t gwin_low_pwr_wakeup_pin_map[] = { GWIN_PIN_UART_RX, };
static const uint8_t gwin_low_pwr_wakeup_pin_cnt = sizeof(gwin_low_pwr_wakeup_pin_map) / sizeof(gwin_low_pwr_wakeup_pin_map[0]);

static uint8_t gwin_low_pwr_enter_allowed = 0;
gwin_low_pwr_wakeup_callback_t gwin_low_pwr_wakeup_callback = NULL;


/**
 * @brief 低功耗 唤醒回调
 */
void gwin_low_pwr_set_callback(gwin_low_pwr_wakeup_callback_t recv_callback)
{
    gwin_low_pwr_wakeup_callback = recv_callback;
}

/**
 * @brief 低功耗 允许
 */
void gwin_low_pwr_set(uint8_t en)
{
    gwin_low_pwr_enter_allowed = (en > 0);
}

/**
 * @brief 低功耗 查询
 */
uint8_t gwin_low_pwr_check(void)
{
    return gwin_low_pwr_enter_allowed;
}

/**
 * @brief 进入低功耗
 */
void gwin_low_pwr_enter(void)
{
    for (uint8_t i = 0; i < gwin_low_pwr_wakeup_pin_cnt; i++)
    {
        System_WakeUpPinEnable(gwin_low_pwr_wakeup_pin_map[i], PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE);
    }
}

/**
 * @brief 退出低功耗
 */
void gwin_low_pwr_exit(void)
{
    gwin_board_init();
}

/**
 * @brief 低功耗唤醒中断
 */
void gwin_low_pwr_interrupt_handler(void)
{
    if (gwin_low_pwr_enter_allowed)             // 避免没有休眠，有休眠唤醒回调
    {
        for (uint8_t i = 0; i < gwin_low_pwr_wakeup_pin_cnt; i++)
        {
            if (System_WakeUpInterruptValue(gwin_low_pwr_wakeup_pin_map[i]) == SET)
            {
                if (gwin_low_pwr_wakeup_callback != NULL)
                {
                    gwin_low_pwr_wakeup_callback(gwin_low_pwr_wakeup_pin_map[i]);
                }

                Pad_ClearWakeupINTPendingBit(gwin_low_pwr_wakeup_pin_map[i]);
            }
            System_WakeUpPinDisable(gwin_low_pwr_wakeup_pin_map[i]);
        }
    }
}


/*----------- ble -----------*/
/**
 * @brief 发送广播
 */
extern uint8_t qr_code[16];
void gwin_ble_adv_send(const uint8_t *data, uint16_t len)
{
    mible_gap_adv_param_t adv_param =
    {
        .adv_interval_min = 0x20,
        .adv_interval_max = 0x40,
        .adv_type = MIBLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED,
        .ch_mask.ch_37_off = 0,
        .ch_mask.ch_38_off = 0,
        .ch_mask.ch_39_off = 0,
    };
    mible_gap_adv_stop();
    mible_gap_adv_data_set(data, len, NULL, 0);
    mible_gap_adv_start(&adv_param);
}

/**
 * @brief 停止发送广播
 */
void gwin_ble_adv_stop(void)
{
    mible_gap_adv_stop();
    // 重新开启系统信息广播
    miio_system_set_adv_timeout(1800000);
}

/**
 * @brief 发送广播
 */
uint8_t gwin_ble_adv_send_with_timems(const uint8_t *data, uint8_t len, uint32_t timems)
{
    return MI_SUCCESS;
}



/**
 * @brief 初始化 动态二维码
 */
#define GWIN_DYNAMIC_QR_CODE                    1
void gwin_dynamic_qr_code_init(void)
{
#if GWIN_DYNAMIC_QR_CODE
    uint8_t mac_addr[6] = { 0x00 };
    uint8_t _mac_addr[6] = { 0x00 };
    gap_get_mac(_mac_addr);
    for (uint8_t i = 0; i < 6; i++)
    {
        mac_addr[i] = _mac_addr[6 - 1 - i];
    }

    static const char *qr_code_base = "www.granchip.com";
    memcpy(qr_code, qr_code_base, sizeof(qr_code));
    for (uint8_t i = 0; i < sizeof(qr_code); i++)
    {
        qr_code[i] = mac_addr[i % 6] ^ qr_code[i];
    }
#endif
}

void gwin_dynamic_qr_code_set(void)
{
    extern void gwin_main_set_adv_dev_pair_info_pkt(const uint8_t *qrcode, uint8_t len);
    gwin_main_set_adv_dev_pair_info_pkt(qr_code, sizeof(qr_code));
}


/*-------------------------- END OF FILE ------------------------------------*/


